Next | Prev | Up | Top | Contents | Index

Fixing the IO4 Problem

A kernel-level device driver for a device that uses DMA in a Challenge-architecture system probably needs to make one change to guard against the IO4 problem.

In order to preclude any chance of data corruption, drivers that are affected must ensure that the IO4 flushes its cache following any DMA write to memory (input from a device). This is done by calling a new kernel function, io4_flush_cache(), in the interrupt routine immediately following completion of any DMA.

The prototype of io4_flush_cache() is

int io4_flush_cache(caddr_t any_PIO_mapaddr);

The argument to the function is any value returned by pio_mapaddr() that is related to the device doing the DMA. The kernel uses this address to locate the IO4 involved. The returned value is 0 when the operation is successful (or was not needed). It is 1 when the argument is not a valid address returned by pio_mapaddr().

The function should be called immediately after the completion of a DMA input to memory. Typically the device produces an interrupt at the end of a DMA, and the function can be called from the interrupt hander. However, some devices can complete more than one DMA transaction per interrupt, and io4_flush_cache() should be called when each DMA completes. Put another way, if it is possible that a data transfer completed after an interrupt, then the driver should call io4_flush_cache() before marking the transaction as complete.

The io4_flush_cache() function does nothing and returns immediately in a machine that has only one IO4 board, and in a machine in which all IO4 boards have the hardware fix.

The kernel's VME interrupt handler calls io4_flush_cache() once on each VME interrupt. Thus a VME device driver only needs to call io4_flush_cache() in the event that it handles the completion of more than DMA transaction per interrupt. For example, a VME-based network driver that handles multiple packets per interrupt should call io4_flush_cache() once for each packet that completes.

Since this problem only affects Challenge/Onyx systems (including POWER Challenge, POWER Onyx, and POWER Challenge R10000), the software fix can and should be conditionally compiled on the compiler variable EVEREST, which is set by /var/sysgen/Makefile.kernio for the affected machines (see "Using /var/sysgen/Makefile.kernio").

The following is a skeletal example of fix code for a hypothetical driver:

#ifdef EVEREST
extern void io4_flush_cache(void* anyPIOMapAddr);
#endif
caddr_t some_PIO_map_addr;
hypothetical_edtinit(...)
{
...
   some_PIO_map_addr = pio_mapaddr(my_piomap, some_dev_addr)
...
}
hypothetical_intr(...)
{
...
#ifdef EVEREST
   io4_flush_cache(some_PIO_map_addr);
#endif
...
}
For another example, see the code of the example VME device driver under "Sample VME Device Driver".



Next | Prev | Up | Top | Contents | Index